using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using NLog;

namespace LDNS.Monitor
{
    /// <summary>
    /// LDNS监控程序入口类
    /// 负责监控LDNS主进程状态并管理DNS设置
    /// 作者：huobing
    /// </summary>
    internal class Program
    {
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private static PortMonitorService? _portMonitorService;
        private static NetworkMonitorService? _networkMonitorService;
        private static readonly object _lockObject = new object();

        /// <summary>
        /// 程序入口点
        /// </summary>
        /// <param name="args">命令行参数，包含父进程ID</param>
        static async Task Main(string[] args)
        {
            ConfigureLogging();
            
            _logger.Info("LDNS监控程序启动");
            
            try
            {
                // 解析命令行参数，获取父进程ID和监控端口
                int parentProcessId;
                List<int> portsToMonitor;
                
                if (!ParseCommandLineArgs(args, out parentProcessId, out portsToMonitor))
                {
                    _logger.Error("无法获取有效的命令行参数，监控程序无法启动");
                    return;
                }

                // 创建并启动端口监控服务
                _portMonitorService = new PortMonitorService(parentProcessId, portsToMonitor, 3000);
                
                // 初始化网络监控服务
                _networkMonitorService = new NetworkMonitorService();
                
                // 注册端口状态变化事件处理程序
                _portMonitorService.PortStatusChanged += OnPortStatusChanged;
                
                // 订阅网络状态变化事件
                _networkMonitorService.NetworkStateChanged += OnNetworkStateChanged;
                
                bool started = _portMonitorService.Start();
                if (!started)
                {
                    _logger.Error("端口监控服务启动失败，程序将退出");
                    return;
                }

                // 启动网络监控服务
                _networkMonitorService.Start();

                // 程序启动时检查DNS端口状态并配置DNS
                _logger.Info("程序启动时检查DNS端口状态...");
                try
                {
                    bool isDnsPortOpen = _portMonitorService.AnyMonitoredPortOpen();
                    _logger.Info($"初始监控端口状态: {(isDnsPortOpen ? "有开放的端口" : "所有端口都已关闭").ToString()}");
                    
                    // 根据初始端口状态配置DNS
                    if (isDnsPortOpen)
                    {
                        _logger.Info("DNS端口开放，设置127.0.0.1为首位DNS服务器...");
                        WindowsDnsManager.SetLocalhostAsPrimaryDns();
                    }
                    else
                    {
                        _logger.Info("DNS端口关闭，从DNS服务器列表中删除127.0.0.1...");
                        WindowsDnsManager.RemoveLocalhostFromDns();
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, "初始化DNS配置时发生异常");
                }

                _logger.Info("监控程序正在后台运行...");

                // 注册退出事件处理程序
                AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
                
                // 保持程序运行
                await Task.Delay(-1);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "监控程序发生未处理异常");
                // 无需控制台输入，直接退出
                Environment.Exit(1);
            }
        }

        /// <summary>
        /// 配置日志
        /// </summary>
        private static void ConfigureLogging()
        {
            // 设置控制台编码
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            Console.InputEncoding = System.Text.Encoding.UTF8;

            // 配置NLog
            string logConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LDNS.Monitor.Nlog.config");
            
            if (File.Exists(logConfigPath))
            {
                // 如果存在配置文件，则加载配置
                LogManager.Setup().LoadConfigurationFromFile(logConfigPath);
            }
            else
            {
                // 默认日志配置
                var config = new NLog.Config.LoggingConfiguration();
                
                // 控制台输出
                var consoleTarget = new NLog.Targets.ConsoleTarget("console")
                {
                    Layout = "${date:format=yyyy-MM-dd HH:mm:ss.fff} [${level:uppercase=true}] ${logger}: ${message} ${exception:format=tostring}",
                    Encoding = System.Text.Encoding.UTF8
                };
                config.AddRule(LogLevel.Info, LogLevel.Fatal, consoleTarget);
                
                // 文件输出
                var fileTarget = new NLog.Targets.FileTarget("file")
                {
                    FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "ldns-monitor-${date:format=yyyy-MM-dd}.log"),
                    Layout = "${date:format=yyyy-MM-dd HH:mm:ss.fff} [${level:uppercase=true}] ${logger}: ${message} ${exception:format=tostring}",
                    Encoding = System.Text.Encoding.UTF8,
                    ArchiveFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "ldns-monitor-${date:format=yyyy-MM-dd}.{#}.log"),
                    ArchiveEvery = NLog.Targets.FileArchivePeriod.Day,
                    MaxArchiveFiles = 7
                };
                config.AddRule(LogLevel.Debug, LogLevel.Fatal, fileTarget);
                
                LogManager.Configuration = config;
            }
        }

        /// <summary>
        /// 解析命令行参数，获取父进程ID和监控端口
        /// </summary>
        /// <param name="args">命令行参数</param>
        /// <param name="parentProcessId">输出：父进程ID</param>
        /// <param name="ports">输出：监控端口列表</param>
        /// <returns>是否解析成功</returns>
        private static bool ParseCommandLineArgs(string[] args, out int parentProcessId, out List<int> ports)
        {
            parentProcessId = -1;
            ports = new List<int>(); // 初始化为空列表，必须通过参数指定
            
            if (args.Length >= 2) // 至少需要父进程ID和端口参数两个参数
            {
                // 第一个参数始终是父进程ID
                try
                {
                    parentProcessId = int.Parse(args[0]);
                    _logger.Info($"从命令行参数获取父进程ID: {parentProcessId}");
                }
                catch (FormatException)
                {
                    _logger.Error($"无效的父进程ID格式: {args[0]}");
                    return false;
                }
                
                // 解析端口参数（格式：port=53,54,80）
                for (int i = 1; i < args.Length; i++)
                {
                    if (args[i].StartsWith("port="))
                    {
                        string portStr = args[i].Substring(5);
                        try
                        {
                            ports.Clear();
                            string[] portValues = portStr.Split(',');
                            foreach (string portValue in portValues)
                            {
                                if (int.TryParse(portValue, out int port) && port > 0 && port <= 65535)
                                {
                                    ports.Add(port);
                                }
                                else
                                {
                                    _logger.Warn($"无效的端口号: {portValue}，将被忽略");
                                }
                            }
                            
                            if (ports.Count == 0)
                            {
                                _logger.Error("未提供有效的端口号，监控程序无法启动");
                                return false;
                            }
                            
                            _logger.Info($"从命令行参数获取监控端口: {string.Join(", ", ports)}");
                        }
                        catch (Exception ex)
                        {
                            _logger.Error(ex, $"解析端口参数失败: {args[i]}");
                            return false; // 端口参数解析失败，程序无法启动
                        }
                    }
                }
                
                // 必须同时满足：父进程ID有效且端口列表不为空
                return parentProcessId > 0 && ports.Count > 0;
            }
            else
            {
                _logger.Error("未提供父进程ID参数");
                return false;
            }
        }

        // 已移除控制台取消键事件处理程序，程序在后台运行

        /// <summary>
        /// 处理进程退出事件
        /// </summary>
        /// <param name="sender">事件源</param>
        /// <param name="e">事件参数</param>
        private static void OnProcessExit(object? sender, EventArgs e)
        {
            _logger.Info("进程退出，正在停止监控服务...");
            _portMonitorService?.Stop();
            _logger.Info("监控程序退出完成");
        }
        
        /// <summary>
        /// 处理端口状态变化事件
        /// 根据端口状态自动配置Windows DNS设置
        /// </summary>
        /// <param name="sender">事件源</param>
        /// <param name="e">事件参数</param>
        private static void OnPortStatusChanged(object? sender, PortStatusChangedEventArgs e)
        {
            lock (_lockObject)
            {
                _logger.Info($"[{e.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] 端口 {e.Port} 状态变化为: {(e.IsOpen ? "开放" : "关闭").ToString()}");
                
                try
                {
                    if (e.IsOpen)
                    {
                        // 端口开放：设置127.0.0.1为首位DNS服务器
                        _logger.Info("DNS端口开放，正在设置127.0.0.1为首位DNS服务器...");
                        bool success = WindowsDnsManager.SetLocalhostAsPrimaryDns();
                        if (success)
                        {
                            _logger.Info("127.0.0.1 DNS服务器设置成功");
                        }
                        else
                        {
                            _logger.Warn("127.0.0.1 DNS服务器设置失败，请检查是否有管理员权限");
                        }
                    }
                    else
                    {
                        // 端口关闭：删除127.0.0.1 DNS服务器
                        _logger.Info("DNS端口关闭，正在从DNS服务器列表中删除127.0.0.1...");
                        bool success = WindowsDnsManager.RemoveLocalhostFromDns();
                        if (success)
                        {
                            _logger.Info("127.0.0.1 DNS服务器删除成功");
                        }
                        else
                        {
                            _logger.Warn("127.0.0.1 DNS服务器删除失败，请检查是否有管理员权限");
                        }
                        
                        // 检查是否所有监控端口都已关闭
                        bool anyMonitoredPortOpen = _portMonitorService != null ? _portMonitorService.AnyMonitoredPortOpen() : false;
                        if (!anyMonitoredPortOpen)
                        {
                            _logger.Info("所有监控端口已关闭，监控程序准备退出");
                            StopMonitoring();
                        }
                    }
                    
                    // 检查当前是否有监控端口处于开放状态
                    bool monitoredPortStatus = _portMonitorService != null ? _portMonitorService.AnyMonitoredPortOpen() : false;
                    if (_logger != null)
                    {
                        _logger.Debug($"当前监控端口状态检查: {(monitoredPortStatus ? "有开放的端口" : "所有端口都已关闭")}");
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, "处理端口状态变化事件时发生异常");
                }
                
                // 其他处理逻辑
                // 1. 端口关闭时发送告警通知
                // 2. 记录端口状态变化到日志或数据库
                // 3. 在需要时尝试重启服务
            }
        }

        /// <summary>
        /// 网络状态变化事件处理程序
        /// </summary>
        /// <param name="sender">事件源</param>
        /// <param name="e">事件参数</param>
        private static void OnNetworkStateChanged(object? sender, EventArgs e)
        {
            lock (_lockObject)
            {
                try
                {
                    _logger.Info("检测到网络状态变化");
                    
                    // 检查当前端口状态，并根据状态设置DNS
                    if (_portMonitorService != null && _portMonitorService.AnyMonitoredPortOpen())
                    {
                        _logger.Info("检测到监控端口开放，确保127.0.0.1为首选DNS服务器");
                        WindowsDnsManager.EnsureLocalhostPrimaryDns();
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, "处理网络状态变化时发生错误");
                }
            }
        }
        
        /// <summary>
        /// 停止监控并退出程序
        /// </summary>
        private static void StopMonitoring()
        {
            _logger.Info("正在停止监控服务并退出程序...");
            _portMonitorService?.Stop();
            _networkMonitorService?.Stop();
            Environment.Exit(0);
        }
    }
}